﻿<%@ WebHandler Language="C#" Class="RbApsResourceBalanceHandler" %>

using System;
using System.Web;
using BusinessRule.DTO;
using System.Web.SessionState;
using DatabaseAccess.DBUtility;
using System.Data.OracleClient;
using System.Data;
using System.Linq;
using System.Text;
using System.Collections.Generic;
using System.Collections;
using Newtonsoft.Json;
using BusinessRule.Business;
using BusinessRule.IBusiness;
using BusinessRule.BusinessFactory;

//Description: 热表设备能力平衡
//Copyright (c) : 通力凯顿（北京）系统集成有限公司
//Writer:zhangrj
//create Date:2024-12-24
public class RbApsResourceBalanceHandler : IHttpHandler, IRequiresSessionState
{
    CurrentUserInfo m_UserInfo;
    LimitedCapacityBusiness limitBusiness = new LimitedCapacityBusiness();//排产类
    public void ProcessRequest(HttpContext context)
    {
        try
        {
            var action = context.Request["action"].ToString();
            m_UserInfo = (CurrentUserInfo)context.Session["CurrentUserInfo"];
            if (m_UserInfo == null)
            {
                context.Response.Write(JsonConvert.SerializeObject(new uMESProcessResult() { Result = false, Message = "登录过期，请重新登录" }));
                return;
            }
            switch (action)
            {
                case "GetApsResourceWeekData": //获取排产设备一周的负荷数据
                    GetApsResourceWeekData(context);
                    break;
                case "GetResourceContainerApsInfo": //获取排产设备的批次排产数据
                    GetResourceContainerApsInfo(context);
                    break;
                default:
                    context.Response.Write(JsonConvert.SerializeObject(new uMESProcessResult() { Result = false, Message = "未知操作" }));
                    break;
            }
        }
        catch (Exception ex)
        {
            uMESProcessResult result = new uMESProcessResult();
            result.Result = false;
            result.Message = ex.Message;
            context.Response.ContentType = "text/html";
            context.Response.Write(JsonConvert.SerializeObject(result));
        }
    }

    /// <summary>
    /// 初始化页面数据
    /// </summary>
    /// <param name="context"></param>
    private void GetApsResourceWeekData(HttpContext context)
    {
        uMESProcessResult result = new uMESProcessResult() { Result = true };
        StringBuilder sqlStr = new StringBuilder();
        sqlStr.AppendFormat(@"SELECT DISTINCT r.resourceid,r.resourcename,r.description resourcedesc,r.workshiftid,wc.workcentername,t.teamname
                            FROM resourcedef r
                            LEFT JOIN Workcenter wc ON wc.workcenterid = r.workcenterid
                            LEFT JOIN team t ON t.teamid = r.teamid
                            LEFT JOIN apsplandetail2 ap ON ap.resourceid = r.resourceid
                            LEFT JOIN containercurrentinfo c ON c.containerid = ap.containerid
                            WHERE r.factoryid = '{0}'", m_UserInfo.FactoryID);
        Dictionary<string, string> dic = JsonConvert.DeserializeObject<Dictionary<string, string>>(context.Request["params"].ToString());
        if (!string.IsNullOrWhiteSpace(dic["WorkCenterId"])) //工区ID
        {
            sqlStr.AppendFormat(" AND r.workcenterid = '{0}'", dic["WorkCenterId"]);
        }
        if (!string.IsNullOrWhiteSpace(dic["TeamId"])) //班组ID
        {
            sqlStr.AppendFormat(" AND r.teamid = '{0}'", dic["TeamId"]);
        }
        if (!string.IsNullOrWhiteSpace(dic["ResourceName"])) //设备名或号
        {
            sqlStr.AppendFormat(" (AND r.resourcename like '%{0}%' OR r.description like '%{0}%')", dic["ResourceName"]);
        }
        if (!string.IsNullOrWhiteSpace(dic["MfgOrderName"])) //订单号
        {
            sqlStr.AppendFormat(" AND c.mfgordername = '{0}'", dic["MfgOrderName"]);
        }
        if (!string.IsNullOrWhiteSpace(dic["ProductName"])) //件号
        {
            sqlStr.AppendFormat(" AND c.productname = '{0}'", dic["ProductName"]);
        }
        if (!string.IsNullOrWhiteSpace(dic["ContainerName"])) //批次号
        {
            sqlStr.AppendFormat(" AND c.containername like '%{0}%'", dic["ContainerName"]);
        }
        //排产开始时间
        if (!string.IsNullOrWhiteSpace(dic["PlanStartTime1"]))
        {
            sqlStr.AppendFormat(" AND ap.starttime >= to_date('{0}','yyyy-mm-dd hh24:mi:ss')", dic["PlanStartTime1"]);
        }
        if (!string.IsNullOrWhiteSpace(dic["PlanStartTime2"]))
        {
            sqlStr.AppendFormat(" AND ap.starttime <= to_date('{0}','yyyy-mm-dd hh24:mi:ss')", dic["PlanStartTime2"]);
        }
        //排产结束时间
        if (!string.IsNullOrWhiteSpace(dic["PlanEndTime1"]))
        {
            sqlStr.AppendFormat(" AND ap.endtime >= to_date('{0}','yyyy-mm-dd hh24:mi:ss')", dic["PlanEndTime1"]);
        }
        if (!string.IsNullOrWhiteSpace(dic["PlanEndTime2"]))
        {
            sqlStr.AppendFormat(" AND ap.endtime <= to_date('{0}','yyyy-mm-dd hh24:mi:ss')", dic["PlanEndTime2"]);
        }
        /*查询出符合条件的设备*/
        DataTable dtResource = DatabaseHelper.Query_ReturnDatTable(sqlStr.ToString());
        if (dtResource.Rows.Count == 0)
        {
            result.Result = false;
            result.Message = "未查询到数据";
            context.Response.Write(JsonConvert.SerializeObject(result));
            return;
        }
        /*开始计算设备一周内的负荷*/
        result = CalculateResourceWeekLoadData(dtResource);
        context.Response.Write(JsonConvert.SerializeObject(result));
    }

    /// <summary>
    /// 计算设备一周内的负荷占比
    /// </summary>
    /// <param name="dtResource"></param>
    /// <returns></returns>
    private uMESProcessResult CalculateResourceWeekLoadData(DataTable dtResource)
    {
        uMESProcessResult result = new uMESProcessResult() { Result = true };
        List<Dictionary<string, string>> colParams = new List<Dictionary<string, string>>();
        int totalTaskCount = 0;//总的任务数
        double averLoad = 0;//平均负荷
        int errorCount = 0;//设备异常数量
        int day = 0;//天数计数器
        do
        {
            double dayAverLoad = 0;//当天的设备平均负荷
            DateTime dayCol = DateTime.Now.AddDays(day);
            string colName = dayCol.ToString("yyyy-MM-dd");//列名
            dtResource.Columns.Add(colName);
            colParams.Add(new Dictionary<string, string>() { { "field", colName }, { "title", dayCol.ToString("MM月dd日") }, { "width", "100" } });//前端列表显示字段
            /*循环设备开始计算*/
            foreach (DataRow item in dtResource.Rows)
            {
                Tuple<double, int> res = GetResourceDayLoad(item, colName);
                item[colName] = string.Format("{0}%", res.Item1);//负荷
                dayAverLoad += res.Item1;
                totalTaskCount += res.Item2;//任务数
            }
            averLoad += Math.Round(dayAverLoad / dtResource.Rows.Count, 2);//计算出这一天的设备平均负荷
            dtResource.AcceptChanges();
            day++;
        } while (day < 7);//不超过7天
        averLoad = Math.Round(averLoad / 7, 2);//计算出平均负荷
        result.RowCount = dtResource.Rows.Count.ToString();
        result.DBTable = dtResource;
        result.ReturnData = new Dictionary<string, object>() { { "colParams", colParams }, { "totalTaskCount", totalTaskCount }, { "averLoad", string.Format("{0}%", averLoad) }, { "errorCount", errorCount } };
        return result;
    }

    /// <summary>
    /// 获取设备一天的负荷数据
    /// </summary>
    /// <param name="drRes">设备数据</param>
    /// <param name="dayTime">日期数据(年-月-日)</param>
    /// <returns>返回参数：负荷数，任务数</returns>
    private Tuple<double, int> GetResourceDayLoad(DataRow drRes, string dayTime)
    {
        /*查询设备的班次总的分钟*/
        int apsMins = 0;
        int totalMins = 0;
        string sql = string.Format(@"SELECT NVL(wsd.mins,0) mins,ws.startdate,ws.enddate,wsd.startdate startdatedetail,wsd.enddate enddatedetail 
                                    FROM Workshift ws 
                                    LEFT JOIN Workshiftdetail wsd ON wsd.workshiftid = ws.workshiftid
                                    WHERE ws.workshiftid = '{0}'", drRes["workshiftid"].ToString());
        DataTable dtWorkShift = DatabaseHelper.Query_ReturnDatTable(sql);
        if (dtWorkShift.Rows.Count == 0) //如果设备班次为空，则取全天作为设备的运作时间
        {
            string wsStartTime = string.Format("{0} {1}", dayTime, "00:00:00");//计算日期的开始时间
            string wsEndTime = string.Format("{0} {1}", dayTime, "23:59:59");//计算日期的结束时间
            totalMins = 1440;//总的分钟便是整个日期的分钟数（24*60）
            /*查询设备的在这个日期内的排产数据*/
            sql = string.Format(@"SELECT ap.starttime,ap.endtime FROM apsplandetail2 ap 
                              WHERE ap.resourceid = '{0}' AND ap.starttime >= to_date('{1}','yyyy-mm-dd hh24:mi:ss') 
                              AND ap.starttime < to_date('{2}','yyyy-mm-dd hh24:mi:ss')", drRes["resourceid"].ToString(), wsStartTime, wsEndTime);
            DataTable dtAps = DatabaseHelper.Query_ReturnDatTable(sql);
            if (dtAps.Rows.Count == 0)
            {
                return new Tuple<double, int>(0, 0);
            }
            foreach (DataRow drAps in dtAps.Rows)
            {
                DateTime apsStartTime = DateTime.Parse(drAps["starttime"].ToString());//排产的开始时间
                DateTime apsEndTime = DateTime.Parse(drAps["endtime"].ToString());//排产的结束时间
                apsMins += (int)limitBusiness.GetDifferMins(apsEndTime, apsStartTime);//直接获取排产的分钟数
            }
            return new Tuple<double, int>(Math.Round((double)((apsMins / totalMins) * 100), 2), dtAps.Rows.Count);
        }
        else
        {
            DateTime wsStartTime = DateTime.Parse(string.Format("{0} {1}", dayTime, dtWorkShift.Rows[0]["startdate"].ToString()));//计算日期的开始时间
            DateTime wsEndTime = DateTime.Parse(string.Format("{0} {1}", dayTime, dtWorkShift.Rows[0]["enddate"].ToString()));//计算日期的结束时间
            totalMins = dtWorkShift.AsEnumerable().Sum(p => int.Parse(p["mins"].ToString()));//班次总的分钟。
            /*查询设备的在这个日期内的排产数据*/
            sql = string.Format(@"SELECT ap.starttime,ap.endtime FROM apsplandetail2 ap 
                              WHERE ap.resourceid = '{0}' AND ap.starttime >= to_date('{1}','yyyy-mm-dd hh24:mi:ss') 
                              AND ap.starttime < to_date('{2}','yyyy-mm-dd hh24:mi:ss')", drRes["resourceid"].ToString(), wsStartTime.ToString(), wsEndTime.ToString());
            DataTable dtAps = DatabaseHelper.Query_ReturnDatTable(sql);
            if (dtAps.Rows.Count == 0)
            {
                return new Tuple<double, int>(0, 0);
            }
            foreach (DataRow drAps in dtAps.Rows)
            {
                DateTime apsStartTime = DateTime.Parse(drAps["starttime"].ToString());//排产的开始时间
                DateTime apsEndTime = DateTime.Parse(drAps["endtime"].ToString());//排产的结束时间
                foreach (DataRow drWs in dtWorkShift.Rows)
                {
                    DateTime wsStartTimeDetail = DateTime.Parse(string.Format("{0} {1}", dayTime, drWs["startdatedetail"].ToString()));//班次明细的开始时间
                    DateTime wsEndTimeDetail = DateTime.Parse(string.Format("{0} {1}", dayTime, drWs["enddatedetail"].ToString()));//班次明细的结束时间
                    if (apsStartTime >= wsEndTimeDetail || apsEndTime < wsEndTimeDetail)//如果工步的排产开始时间大于班次明细的结束时间 或者 排产结束时间小于班次明细的开始时间，则跳过
                    {
                        continue;
                    }
                    else if (apsStartTime >= wsStartTimeDetail && apsEndTime <= wsEndTimeDetail)//如果工步的排产时间在这个班次明细内，则计算排产的分钟即可。
                    {
                        apsMins += (int)limitBusiness.GetDifferMins(apsEndTime, apsStartTime);
                    }
                    else if (apsStartTime >= wsStartTimeDetail && apsEndTime > wsEndTimeDetail) //如果工步的排产开始时间在班次明细范围内，但是结束时间不在，则结束时间取班次明细结束时间。
                    {
                        apsMins += (int)limitBusiness.GetDifferMins(wsEndTimeDetail, apsStartTime);
                    }
                    else if (apsStartTime < wsStartTimeDetail && apsEndTime < wsEndTimeDetail) //如果工步的排产开始时间不在班次明细范围内，但是结束时间在，则开始时间取班次明细开始时间。
                    {
                        apsMins += (int)limitBusiness.GetDifferMins(apsEndTime, wsStartTimeDetail);
                    }
                    else if (apsStartTime < wsStartTimeDetail && apsEndTime > wsEndTimeDetail) //如果工步的排产时间范围包含了班次明细，则取班次明细即可。
                    {
                        apsMins += (int)limitBusiness.GetDifferMins(wsEndTimeDetail, wsStartTimeDetail);
                    }
                }
            }
            return new Tuple<double, int>(Math.Round((double)((apsMins / totalMins) * 100), 2), dtAps.Rows.Count);
        }
    }

    /// <summary>
    /// 获取设备的批次排产信息
    /// </summary>
    /// <param name="context"></param>
    private void GetResourceContainerApsInfo(HttpContext context)
    {
        uMESProcessResult result = new uMESProcessResult() { Result = true };
        /*查询设备的班次总的分钟*/
        string sql = string.Format(@"SELECT ws.startdate,ws.enddate
                                    FROM resourcedef r
                                    LEFT JOIN Workshift ws ON ws.workshiftid = r.workshiftid
                                    WHERE r.resourceid = '{0}'", context.Request["resourceid"].ToString());
        DataTable dtWorkShift = DatabaseHelper.Query_ReturnDatTable(sql);
        int day = 0;
        string startTime = dtWorkShift.Rows.Count == 0 ? "00:00:00" : dtWorkShift.Rows[0]["startdate"].ToString();//计算日期的开始时间
        string endTime = dtWorkShift.Rows.Count == 0 ? "23:59:59" : dtWorkShift.Rows[0]["enddate"].ToString();//计算日期的结束时间
        /*查询设备的任务*/
        StringBuilder sqlb = new StringBuilder();
        DataTable dtAps = new DataTable();
        do
        {
            string dayTime = DateTime.Now.AddDays(day).ToString("yyyy-mm-dd");
            string cuStartTime = string.Format("{0} {1}", dayTime, startTime);
            string cuEndTime = string.Format("{0} {1}", dayTime, endTime);
            /*查询设备的在这个日期内的排产数据*/
            sql = string.Format(@"SELECT c.containername,s.stepno,s.description stepdesc,ap.starttime,ap.endtime FROM apsplandetail2 ap
                              LEFT JOIN containercurrentinfo c ON c.containerid = ap.containerid
                              LEFT JOIN stepinfo s ON s.stepinfoid = ap.stepinfoid
                              WHERE ap.resourceid = '{0}' 
                              AND ap.starttime >= to_date('{1}','yyyy-mm-dd hh24:mi:ss') 
                              AND ap.starttime < to_date('{2}','yyyy-mm-dd hh24:mi:ss')", context.Request["resourceid"].ToString(), cuStartTime, cuEndTime);
            dtAps.Merge(DatabaseHelper.Query_ReturnDatTable(sql));
            day++;
        } while (day < 7);
        result.DBTable = dtAps;
        context.Response.Write(JsonConvert.SerializeObject(result));
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }

}